home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / termlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-19  |  13.5 KB  |  618 lines

  1. /* vi:set ts=8 sts=4 sw=4: */
  2. /*
  3.  * The following software is (C) 1984 Peter da Silva, the Mad Australian, in
  4.  * the public domain. It may be re-distributed for any purpose with the
  5.  * inclusion of this notice.
  6.  */
  7.  
  8. /* Modified by Bram Moolenaar for use with VIM - Vi Improved. */
  9. /* A few bugs removed by Olaf 'Rhialto' Seibert. */
  10.  
  11. /* TERMLIB: Terminal independant database. */
  12.  
  13. #include "vim.h"
  14. #include "termlib.pro"
  15.  
  16. #if !defined(AMIGA) && !defined(VMS) && !defined(macintosh)
  17. # include <sgtty.h>
  18. #endif
  19.  
  20. static int  getent __ARGS((char *, char *, FILE *, int));
  21. static int  nextent __ARGS((char *, FILE *, int));
  22. static int  _match __ARGS((char *, char *));
  23. static char *_addfmt __ARGS((char *, char *, int));
  24. static char *_find __ARGS((char *, char *));
  25.  
  26. /*
  27.  * Global variables for termlib
  28.  */
  29.  
  30. char    *tent;              /* Pointer to terminal entry, set by tgetent */
  31. char    PC = 0;              /* Pad character, default NULL */
  32. char    *UP = 0, *BC = 0;     /* Pointers to UP and BC strings from database */
  33. short    ospeed;              /* Baud rate (1-16, 1=300, 16=19200), as in stty */
  34.  
  35. /*
  36.  * Module: tgetent
  37.  *
  38.  * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
  39.  *
  40.  * Calling conventions: char tbuf[TBUFSZ+], term=canonical name for terminal.
  41.  *
  42.  * Returned values: 1 = success, -1 = can't open file,
  43.  *        0 = can't find terminal.
  44.  *
  45.  * Notes:
  46.  * - Should probably supply static buffer.
  47.  * - Uses environment variables "TERM" and "TERMCAP". If TERM = term (that is,
  48.  *   if the argument matches the environment) then it looks at TERMCAP.
  49.  * - If TERMCAP begins with a slash, then it assumes this is the file to
  50.  *   search rather than /etc/termcap.
  51.  * - If TERMCAP does not begin with a slash, and it matches TERM, then this is
  52.  *   used as the entry.
  53.  * - This could be simplified considerably for non-UNIX systems.
  54.  */
  55.  
  56. #ifdef AMIGA
  57. # define TERMCAPFILE "s:termcap"
  58. #else
  59. # define TERMCAPFILE "/etc/termcap"
  60. #endif
  61.  
  62. tgetent(tbuf, term)
  63.     char    *tbuf;        /* Buffer to hold termcap entry, TBUFSZ bytes max */
  64.     char    *term;        /* Name of terminal */
  65. {
  66.     char    tcbuf[32];        /* Temp buffer to handle */
  67.     char    *tcptr = tcbuf;    /* extended entries */
  68.     char    *tcap = TERMCAPFILE; /* Default termcap file */
  69.     char    *tmp;
  70.     FILE    *termcap;
  71.     int        retval = 0;
  72.     int        len;
  73.  
  74.     if ((tmp = (char *)vim_getenv((char_u *)"TERMCAP")) != NULL)
  75.     {
  76.     if (*tmp == '/')        /* TERMCAP = name of termcap file */
  77.     {
  78.         tcap = tmp ;
  79. #if defined(AMIGA)
  80.         /* Convert /usr/share/lib/termcap to usr:share/lib/termcap */
  81.         tcap++;
  82.         tmp = strchr(tcap, '/');
  83.         if (tmp)
  84.         *tmp = ':';
  85. #endif
  86.     }
  87.     else                /* TERMCAP = termcap entry itself */
  88.     {
  89.         int tlen = strlen(term);
  90.  
  91.         while (*tmp && *tmp != ':')        /* Check if TERM matches */
  92.         {
  93.         char *nexttmp;
  94.  
  95.         while (*tmp == '|')
  96.             tmp++;
  97.         nexttmp  = _find(tmp, ":|");    /* Rhialto */
  98.         if (tmp+tlen == nexttmp && _match(tmp, term) == tlen)
  99.         {
  100.             strcpy(tbuf, tmp);
  101.             tent = tbuf;
  102.             return 1;
  103.         }
  104.         else
  105.             tmp = nexttmp;
  106.         }
  107.     }
  108.     }
  109.     if (!(termcap = fopen(tcap, "r")))
  110.     {
  111.     strcpy(tbuf, tcap);
  112.     return -1;
  113.     }
  114.  
  115.     len = 0;
  116.     while (getent(tbuf + len, term, termcap, TBUFSZ - len))
  117.     {
  118.     tcptr = tcbuf;                /* Rhialto */
  119.     if ((term = tgetstr("tc", &tcptr)))    /* extended entry */
  120.     {
  121.         rewind(termcap);
  122.         len = strlen(tbuf);
  123.     }
  124.     else
  125.     {
  126.         retval = 1;
  127.         tent = tbuf;    /* reset it back to the beginning */
  128.         break;
  129.     }
  130.     }
  131.     fclose(termcap);
  132.     return retval;
  133. }
  134.  
  135.     static int
  136. getent(tbuf, term, termcap, buflen)
  137.     char    *tbuf, *term;
  138.     FILE    *termcap;
  139.     int        buflen;
  140. {
  141.     char    *tptr;
  142.     int        tlen = strlen(term);
  143.  
  144.     while (nextent(tbuf, termcap, buflen))    /* For each possible entry */
  145.     {
  146.     tptr = tbuf;
  147.     while (*tptr && *tptr != ':')        /* : terminates name field */
  148.     {
  149.         char    *nexttptr;
  150.  
  151.         while (*tptr == '|')        /* | seperates names */
  152.         tptr++;
  153.         nexttptr = _find(tptr, ":|");    /* Rhialto */
  154.         if (tptr + tlen == nexttptr &&
  155.         _match(tptr, term) == tlen)    /* FOUND! */
  156.         {
  157.         tent = tbuf;
  158.         return 1;
  159.         }
  160.         else                /* Look for next name */
  161.         tptr = nexttptr;
  162.     }
  163.     }
  164.     return 0;
  165. }
  166.  
  167.     static int
  168. nextent(tbuf, termcap, buflen)        /* Read 1 entry from TERMCAP file */
  169.     char    *tbuf;
  170.     FILE    *termcap;
  171.     int        buflen;
  172. {
  173.     char *lbuf = tbuf;                /* lbuf=line buffer */
  174.                 /* read lines straight into buffer */
  175.  
  176.     while (lbuf < tbuf+buflen &&        /* There's room and */
  177.       fgets(lbuf, (int)(tbuf+buflen-lbuf), termcap)) /* another line */
  178.     {
  179.     int llen = strlen(lbuf);
  180.  
  181.     if (*lbuf == '#')            /* eat comments */
  182.         continue;
  183.     if (lbuf[-1] == ':' &&            /* and whitespace */
  184.         lbuf[0] == '\t' &&
  185.         lbuf[1] == ':')
  186.     {
  187.         strcpy(lbuf, lbuf+2);
  188.         llen -= 2;
  189.     }
  190.     if (lbuf[llen-2] == '\\')        /* and continuations */
  191.         lbuf += llen-2;
  192.     else
  193.     {
  194.         lbuf[llen-1]=0;            /* no continuation, return */
  195.         return 1;
  196.     }
  197.     }
  198.  
  199.     return 0;                    /* ran into end of file */
  200. }
  201.  
  202. /*
  203.  * Module: tgetflag
  204.  *
  205.  * Purpose: returns flag true or false as to the existence of a given entry.
  206.  * used with 'bs', 'am', etc...
  207.  *
  208.  * Calling conventions: id is the 2 character capability id.
  209.  *
  210.  * Returned values: 1 for success, 0 for failure.
  211.  */
  212.  
  213. tgetflag(id)
  214.     char *id;
  215. {
  216.     char    buf[256], *ptr = buf;
  217.  
  218.     return tgetstr(id, &ptr) ? 1 : 0;
  219. }
  220.  
  221. /*
  222.  * Module: tgetnum
  223.  *
  224.  * Purpose: get numeric value such as 'li' or 'co' from termcap.
  225.  *
  226.  * Calling conventions: id = 2 character id.
  227.  *
  228.  * Returned values: -1 for failure, else numerical value.
  229.  */
  230.  
  231. tgetnum(id)
  232.     char *id;
  233. {
  234.     char *ptr, buf[256];
  235.     ptr = buf;
  236.  
  237.     if (tgetstr(id, &ptr))
  238.     return atoi(buf);
  239.     else
  240.     return 0;
  241. }
  242.  
  243. /*
  244.  * Module: tgetstr
  245.  *
  246.  * Purpose: get terminal capability string from database.
  247.  *
  248.  * Calling conventions: id is the two character capability id.
  249.  *        (*buf) points into a hold buffer for the
  250.  *        id. the capability is copied into the buffer
  251.  *        and (*buf) is advanced to point to the next
  252.  *        free byte in the buffer.
  253.  *
  254.  * Returned values: 0 = no such entry, otherwise returns original
  255.  *        (*buf) (now a pointer to the string).
  256.  *
  257.  * Notes
  258.  *    It also decodes certain escape sequences in the buffer.
  259.  *  they should be obvious from the code:
  260.  *    \E = escape.
  261.  *    \n, \r, \t, \f, \b match the 'c' escapes.
  262.  *    ^x matches control-x (^@...^_).
  263.  *    \nnn matches nnn octal.
  264.  *    \x, where x is anything else, matches x. I differ
  265.  *  from the standard library here, in that I allow ^: to match
  266.  *  :.
  267.  *
  268.  */
  269.  
  270.     char *
  271. tgetstr(id, buf)
  272.     char    *id, **buf;
  273. {
  274.     int        len = strlen(id);
  275.     char    *tmp=tent;
  276.     char    *hold;
  277.     int        i;
  278.  
  279.     do {
  280.     tmp = _find(tmp, ":");            /* For each field */
  281.     while (*tmp == ':')            /* skip empty fields */
  282.         tmp++;
  283.     if (!*tmp)
  284.         break;
  285.  
  286.     if (_match(id, tmp) == len) {
  287.         tmp += len;                /* find '=' '@' or '#' */
  288.         if (*tmp == '@')            /* :xx@: entry for tc */
  289.         return 0;            /* deleted entry */
  290.         hold= *buf;
  291.         while (*++tmp && *tmp != ':') {    /* not at end of field */
  292.         switch(*tmp) {
  293.         case '\\':            /* Expand escapes here */
  294.             switch(*++tmp) {
  295.             case 0:            /* ignore backslashes */
  296.             tmp--;            /* at end of entry */
  297.             break;            /* shouldn't happen */
  298.             case 'e':
  299.             case 'E':            /* ESC */
  300.             *(*buf)++ = '\033';
  301.             break;
  302.             case 'n':            /* \n */
  303.             *(*buf)++ = '\n';
  304.             break;
  305.             case 'r':            /* \r */
  306.             *(*buf)++ = '\r';
  307.             break;
  308.             case 't':            /* \t */
  309.             *(*buf)++ = '\t';
  310.             break;
  311.             case 'b':            /* \b */
  312.             *(*buf)++ = '\b';
  313.             break;
  314.             case 'f':            /* \f */
  315.             *(*buf)++ = '\f';
  316.             break;
  317.             case '0':            /* \nnn */
  318.             case '1':
  319.             case '2':
  320.             case '3':
  321.             case '4':
  322.             case '5':
  323.             case '6':
  324.             case '7':
  325.             case '8':
  326.             case '9':
  327.             **buf = 0;
  328.                 /* get up to three digits */
  329.             for (i = 0; i < 3 && isdigit(*tmp); ++i)
  330.                 **buf = **buf * 8 + *tmp++ - '0';
  331.             (*buf)++;
  332.             tmp--;
  333.             break;
  334.             default:            /* \x, for all other x */
  335.             *(*buf)++= *tmp;
  336.             }
  337.             break;
  338.         case '^':            /* control characters */
  339.             *(*buf)++ = *++tmp - '@';
  340.             break;
  341.         default:
  342.             *(*buf)++ = *tmp;
  343.         }
  344.         }
  345.         *(*buf)++ = 0;
  346.         return hold;
  347.     }
  348.     } while (*tmp);
  349.  
  350.     return 0;
  351. }
  352.  
  353. /*
  354.  * Module: tgoto
  355.  *
  356.  * Purpose: decode cm cursor motion string.
  357.  *
  358.  * Calling conventions: cm is cursor motion string.  line, col, are the
  359.  * desired destination.
  360.  *
  361.  * Returned values: a string pointing to the decoded string, or "OOPS" if it
  362.  * cannot be decoded.
  363.  *
  364.  * Notes
  365.  *    The accepted escapes are:
  366.  *    %d     as in printf, 0 origin.
  367.  *    %2, %3   like %02d, %03d in printf.
  368.  *    %.     like %c
  369.  *    %+x     adds <x> to value, then %.
  370.  *    %>xy     if value>x, adds y. No output.
  371.  *    %i     increments line& col, no output.
  372.  *    %r     reverses order of line&col. No output.
  373.  *    %%     prints as a single %.
  374.  *    %n     exclusive or row & col with 0140.
  375.  *    %B     BCD, no output.
  376.  *    %D     reverse coding (x-2*(x%16)), no output.
  377.  */
  378.  
  379.     char *
  380. tgoto(cm, col, line)
  381.     char    *cm;                /* cm string, from termcap */
  382.     int col,                    /* column, x position */
  383.     line;                    /* line, y position */
  384. {
  385.     char    gx, gy,                /* x, y */
  386.     *ptr,                    /* pointer in 'cm' */
  387.     reverse = 0,                /* reverse flag */
  388.     *bufp,                    /* pointer in returned string */
  389.     addup = 0,                /* add upline */
  390.     addbak = 0,                /* add backup */
  391.     c;
  392.     static char buffer[32];
  393.  
  394.     if (!cm)
  395.     return "OOPS";                /* Kludge, but standard */
  396.  
  397.     bufp = buffer;
  398.     ptr = cm;
  399.  
  400.     while (*ptr) {
  401.     if ((c = *ptr++) != '%') {        /* normal char */
  402.         *bufp++ = c;
  403.     } else {                /* % escape */
  404.         switch(c = *ptr++) {
  405.         case 'd':                /* decimal */
  406.         bufp = _addfmt(bufp, "%d", line);
  407.         line = col;
  408.         break;
  409.         case '2':                /* 2 digit decimal */
  410.         bufp = _addfmt(bufp, "%02d", line);
  411.         line = col;
  412.         break;
  413.         case '3':                /* 3 digit decimal */
  414.         bufp = _addfmt(bufp, "%03d", line);
  415.         line = col;
  416.         break;
  417.         case '>':                /* %>xy: if >x, add y */
  418.         gx = *ptr++;
  419.         gy = *ptr++;
  420.         if (col>gx) col += gy;
  421.         if (line>gx) line += gy;
  422.         break;
  423.         case '+':                /* %+c: add c */
  424.         line += *ptr++;
  425.         case '.':                /* print x/y */
  426.         if (line == '\t' ||        /* these are */
  427.            line == '\n' ||        /* chars that */
  428.            line == '\004' ||        /* UNIX hates */
  429.            line == '\0') {
  430.             line++;            /* so go to next pos */
  431.             if (reverse == (line == col))
  432.             addup=1;        /* and mark UP */
  433.             else
  434.             addbak=1;        /* or BC */
  435.         }
  436.         *bufp++=line;
  437.         line = col;
  438.         break;
  439.         case 'r':                /* r: reverse */
  440.         gx = line;
  441.         line = col;
  442.         col = gx;
  443.         reverse = 1;
  444.         break;
  445.         case 'i':            /* increment (1-origin screen) */
  446.         col++;
  447.         line++;
  448.         break;
  449.         case '%':                /* %%=% literally */
  450.         *bufp++='%';
  451.         break;
  452.         case 'n':                /* magic DM2500 code */
  453.         line ^= 0140;
  454.         col ^= 0140;
  455.         break;
  456.         case 'B':                /* bcd encoding */
  457.         line = line/10<<4+line%10;
  458.         col = col/10<<4+col%10;
  459.         break;
  460.         case 'D':                /* magic Delta Data code */
  461.         line = line-2*(line&15);
  462.         col = col-2*(col&15);
  463.         break;
  464.         default:                /* Unknown escape */
  465.         return "OOPS";
  466.         }
  467.     }
  468.     }
  469.  
  470.     if (addup)                    /* add upline */
  471.     if (UP) {
  472.         ptr=UP;
  473.         while (isdigit(*ptr) || *ptr == '.')
  474.         ptr++;
  475.         if (*ptr == '*')
  476.         ptr++;
  477.         while (*ptr)
  478.         *bufp++ = *ptr++;
  479.     }
  480.  
  481.     if (addbak)                    /* add backspace */
  482.     if (BC) {
  483.         ptr=BC;
  484.         while (isdigit(*ptr) || *ptr == '.')
  485.         ptr++;
  486.         if (*ptr == '*')
  487.         ptr++;
  488.         while (*ptr)
  489.         *bufp++ = *ptr++;
  490.     }
  491.     else
  492.         *bufp++='\b';
  493.  
  494.     *bufp = 0;
  495.  
  496.     return(buffer);
  497. }
  498.  
  499. /*
  500.  * Module: tputs
  501.  *
  502.  * Purpose: decode padding information
  503.  *
  504.  * Calling conventions: cp = string to be padded, affcnt = # of items affected
  505.  *    (lines, characters, whatever), outc = routine to output 1 character.
  506.  *
  507.  * Returned values: none
  508.  *
  509.  * Notes
  510.  *    cp has padding information ahead of it, in the form
  511.  *  nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay,
  512.  *  and may be a decimal (nnn.mmm). If the asterisk is given, then
  513.  *  the delay is multiplied by afcnt. The delay is produced by outputting
  514.  *  a number of nulls (or other padding char) after printing the
  515.  *  TEXT.
  516.  *
  517.  */
  518.  
  519. long _bauds[16]={
  520.     0,    50, 75,    110,
  521.     134,    150,    200,    300,
  522.     600,    1200,   1800,   2400,
  523.     4800,   9600,   19200,  19200 };
  524.  
  525. tputs(cp, affcnt, outc)
  526.     char *cp;                /* string to print */
  527.     int affcnt;                /* Number of lines affected */
  528.     void (*outc) __ARGS((unsigned int));/* routine to output 1 character */
  529. {
  530.     long    frac,            /* 10^(#digits after decimal point) */
  531.     counter,            /* digits */
  532.     atol __ARGS((const char *));
  533.  
  534.     if (isdigit(*cp)) {
  535.     counter = 0;
  536.     frac = 1000;
  537.     while (isdigit(*cp))
  538.         counter = counter * 10L + (long)(*cp++ - '0');
  539.     if (*cp == '.')
  540.         while (isdigit(*++cp)) {
  541.         counter = counter * 10L + (long)(*cp++ - '0');
  542.         frac = frac * 10;
  543.         }
  544.     if (*cp!='*') {            /* multiply by affected lines */
  545.         if (affcnt>1) affcnt = 1;
  546.     }
  547.     else
  548.         cp++;
  549.  
  550.     /* Calculate number of characters for padding counter/frac ms delay */
  551.     if (ospeed)
  552.         counter = (counter * _bauds[ospeed] * (long)affcnt) / frac;
  553.  
  554.     while (*cp)            /* output string */
  555.         (*outc)(*cp++);
  556.     if (ospeed)
  557.         while (counter--)        /* followed by pad characters */
  558.         (*outc)(PC);
  559.     }
  560.     else
  561.     while (*cp)
  562.         (*outc)(*cp++);
  563.     return 0;
  564. }
  565.  
  566. /*
  567.  * Module: tutil.c
  568.  *
  569.  * Purpose: Utility routines for TERMLIB functions.
  570.  *
  571.  */
  572.     static int
  573. _match(s1, s2)        /* returns length of text common to s1 and s2 */
  574.     char *s1, *s2;
  575. {
  576.     int i = 0;
  577.  
  578.     while (s1[i] && s1[i] == s2[i])
  579.     i++;
  580.  
  581.     return i;
  582. }
  583.  
  584. /*
  585.  * finds next c in s that's a member of set, returns pointer
  586.  */
  587.     static char *
  588. _find(s, set)
  589.     char *s, *set;
  590. {
  591.     for(; *s; s++)
  592.     {
  593.     char    *ptr = set;
  594.  
  595.     while (*ptr && *s != *ptr)
  596.         ptr++;
  597.  
  598.     if (*ptr)
  599.         return s;
  600.     }
  601.  
  602.     return s;
  603. }
  604.  
  605. /*
  606.  * add val to buf according to format fmt
  607.  */
  608.     static char *
  609. _addfmt(buf, fmt, val)
  610.     char *buf, *fmt;
  611.     int val;
  612. {
  613.     sprintf(buf, fmt, val);
  614.     while (*buf)
  615.     buf++;
  616.     return buf;
  617. }
  618.